﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web.Configuration;
using System.Xml.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace SharePointSiteConfigurator
{
    /// <summary>
    /// SharePointSiteConfigurator class, contains functions for configuring sites and subsites
    /// </summary>
    public class SiteConfigurator
    {
        #region Properties
        private string siteUrl;
        private XElement siteConfigurations;
        private string siteConfigurationName;
        XElement webConfigSiteConfigurationsOverride = null;
#if SP2010
        private TraceLogger2010 mtr;
#else
        private TraceLogger mtr;
#endif
        #endregion

        /// <summary>
        /// Initializing SharePointSiteConfigurator
        /// </summary>
        /// <param name="siteUrl"></param>
        /// <param name="siteConfigurations"></param>
        /// <param name="siteConfigurationName"></param>
        public SiteConfigurator(string siteUrl, XElement siteConfigurations, string siteConfigurationName)
        {
            this.siteUrl = siteUrl;
            this.siteConfigurations = siteConfigurations;
            this.siteConfigurationName = siteConfigurationName;

#if SP2010
            mtr = new TraceLogger2010("SiteConfigurator", SPFarm.Local);
#else
            mtr = TraceLogger.Instance;
#endif
        }

        /// <summary>
        /// Loads the methods in the order the properties in the siteconfiguration files is listed.
        /// </summary>
        private void LoadMethodsDynamic(SPSite site, SPWeb web)
        {
            IEnumerable<XElement> items = GetSiteConfigurationElements();
            if (items == null) items = GetSiteConfigurationElementsWithoutXmlns();
            if (items == null) mtr.TraceVerboseMessage("Cannot find any siteconfigurations elements defined");
            foreach (XElement item in items)
            {
                try
                {
                    #region switch
                    string configPropertyName = item.Name.LocalName;
                    switch (configPropertyName)
                    {
                        case "SetSiteCollectionAdministrators":
                            SharePointUtilities.SetSiteCollectionAdministrators(web, item, webConfigSiteConfigurationsOverride);
                            break;
                        case "SiteCollectionInformationManagementPolicy":
                            SharePointUtilities.CreateSiteCollectionInformationManagementPolicies(site, item);
                            break;
                        case "SiteCollectionInformationManagementPolicyContentTypeAssociation":
                            SharePointUtilities.AddSiteCollectionInformationManagementPolicyContentTypeAssociations(site, web, item);
                            break;
                        case "SiteCollectionFeature":
                            SharePointUtilities.ActivateSiteCollectionFeature(web, item);
                            break;
                        case "ApplyTheme2010":
                            SharePointUtilities.ApplyTheme2010(site, item);
                            break;
                        case "ConfigureSubSite":
                            SharePointUtilities.ConfigureSubSite(site, item, webConfigSiteConfigurationsOverride);
                            break;
                        default: // do webMethods...
                            SharePointUtilities.WebMethodsDynamic(web, item, webConfigSiteConfigurationsOverride);
                            break;
                    }
                    #endregion

                }
                catch (Exception ex)
                {
                    mtr.TraceError("Failed to apply the configuration element : " + item.ToString(), ex);
                }
            }
        }

        private void LoadDeleteMethodsDynamic(SPSite site, SPWeb web)
        {
            IEnumerable<XElement> items = GetSiteConfigurationElements();
            foreach (XElement item in items)
            {
                string configPropertyName = item.Name.LocalName;
                switch (configPropertyName)
                {
                    //case "SiteCollectionFeature":
                    //    SharePointUtilities.DeactivateSiteCollectionFeatures(web, item);
                    //    break;
                    case "TopNavigationToDelete":
                        SharePointUtilities.DeleteTopNavigationLinks(web);
                        break;
                    case "DeleteQuickLaunchLinks":
                        SharePointUtilities.DeleteQuickLaunchLinks(web);
                        break;
                    //case "WebFeature":
                    //    SharePointUtilities.DeactivateWebFeatures(web, item);
                    //    break;
                    case "DeleteListInstance":
                        SharePointUtilities.DeleteList(web, item);
                        break;
                    //case "DeleteWebParts":
                    //    SharePointUtilities.DeleteWebParts(web, item);
                    //    break;
                    //case "PropertyBag":
                    //    SharePointUtilities.RemovePropertyBag(web, item);
                    //    break;
                    //case "FileToProvision":
                    //    SharePointUtilities.UnprovisionFiles(web, item);
                    //    break;
                    default: // do nothing...
                        break;
                }
            }
        }
        /// <summary>
        /// Run starts the main program. Called from feature activated
        /// </summary>
        public void Run()
        {
            mtr.TraceVerboseMessage("STARTING RUN()");

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                try
                {
                    XElement webConfigSection = GetWebConfigSiteConfigurations();
                    webConfigSiteConfigurationsOverride = GetWebConfigOverrideSectionsForSiteTemplate(webConfigSection);
                }
                catch (Exception ex)
                {
                    mtr.TraceError("Failed to load SiteConfigurations from web.config", ex);
                    webConfigSiteConfigurationsOverride = new XElement("SiteConfigurations");
                }
                using (SPSite site = new SPSite(siteUrl))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        mtr.TraceVerboseMessage(string.Format(" Run started with the following parameters: sitetemplate={0}, siteUrl={1}, siteConfigurationName={2}", web.WebTemplate, siteUrl, siteConfigurationName));

                        web.AllowUnsafeUpdates = true;
                        LoadMethodsDynamic(site, web);
                        web.AllowUnsafeUpdates = false;
                    }
                }
            });
            mtr.TraceVerboseMessage("RUN() IS COMPLETED");
        }

        /// <summary>
        /// Cleans out the main parts and lists specified in the config file
        /// </summary>
        public void RunCleanUp()
        {
            using (SPSite site = new SPSite(siteUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    mtr.TraceVerboseMessage("Starting RunCleanUp()");
                    web.AllowUnsafeUpdates = true;
                    LoadDeleteMethodsDynamic(site, web);
                    web.AllowUnsafeUpdates = false;
                }
            }
            mtr.TraceVerboseMessage("Completed RunCleanUp()");
        }


        #region XMLParse&Reading



        private IEnumerable<XElement> GetSiteConfigurationElements()
        {
            mtr.TraceVerboseMessage("Trying to read the configuration elements with xmlns defined");
            IEnumerable<XElement> configurationXML =
                from s in siteConfigurations.Elements("{http://tempuri.org/siteconfigurator.xsd}SiteConfiguration")
                where s.Attribute("Name").Value == this.siteConfigurationName
                select s;
            IEnumerable<XElement> items = configurationXML.Elements();
            return items;
        }

        private IEnumerable<XElement> GetSiteConfigurationElementsWithoutXmlns()
        {
            mtr.TraceVerboseMessage("Could not find any elements with Xmlns defined.");
            mtr.TraceVerboseMessage("Trying to read the configuration elements without xmlns defined");
            IEnumerable<XElement> configurationXML =
                from s in siteConfigurations.Elements("SiteConfiguration")
                where s.Attribute("Name").Value == this.siteConfigurationName
                select s;
            IEnumerable<XElement> items = configurationXML.Elements();
            return items;
        }

        /// <summary>
        /// Gets the web config settings for overriding site configurations.
        /// </summary>
        /// <returns>The site configurations from web config for the selected siteconfiguration (template).</returns>
        private XElement GetWebConfigSiteConfigurations()
        {
            XElement overrideSiteConfigurations = null;
            Configuration webConfigOverrides = null;
            try
            {
                webConfigOverrides = WebConfigurationManager.OpenWebConfiguration("/");
                ConfigurationSectionGroup siteConfig = webConfigOverrides.GetSectionGroup("SharePointSiteConfigurator");

                if (siteConfig != null)
                {
                    if (siteConfig.Sections.Count > 1) mtr.TraceVerboseMessage("Warning! There are more than one override section in web.config. Using the first.");
                    overrideSiteConfigurations = XElement.Parse(siteConfig.Sections[0].SectionInformation.GetRawXml());
                }
                else
                {
                    overrideSiteConfigurations = new XElement("SiteConfigurations");
                    mtr.TraceVerboseMessage("Overridesection not found. Returning blank override section");
                }
            }
            catch (ConfigurationErrorsException ex)
            {
                mtr.TraceError("Could not OpenWebConfiguration(\"~\")", ex);
                mtr.TraceVerboseMessage("Returning blank override section");
                overrideSiteConfigurations = new XElement("SiteConfigurations");
            }
            catch (Exception ex)
            {
                mtr.TraceError("An error occured trying to load web.config override sections", ex);
                mtr.TraceVerboseMessage("Returning blank override section");
                overrideSiteConfigurations = new XElement("SiteConfigurations");
            }
            return overrideSiteConfigurations;
        }


        private XElement GetWebConfigOverrideSectionsForSiteTemplate(XElement webConfigSection)
        {
            mtr.TraceVerboseMessage("Starting GetWebConfigOverrideSectionsForSiteTemplate");
            mtr.TraceVerboseMessage("Selecting only the override elements valid for the selected siteconfiguration (template)");
            IEnumerable<XElement> configurationXML =
                from s in webConfigSection.Elements("SiteConfiguration")
                where s.Attribute("Name").Value == this.siteConfigurationName
                select s;
            XElement item = configurationXML.FirstOrDefault();
            return item;
        }


        #endregion

    }
}
